package com.qen.repository;

import com.alibaba.fastjson2.JSONObject;
import com.qen.common.BeetlUtils;
import org.beetl.sql.core.page.DefaultPageRequest;
import org.beetl.sql.core.page.PageRequest;
import org.beetl.sql.core.page.PageResult;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * 操作非 当前对象 的实体数据库操作
 *
 * @author licz
 * @data 2025年05月14日 4:33 PM
 */
public interface HandDao {

    /**
     * 查对象
     *
     * @param key
     * @param clz
     * @param <E>
     * @return
     */
    <E> E findObjectByKey(Serializable key, Class<E> clz);

    /**
     * 查对象
     *
     * @param keys
     * @param clz
     * @param <E>
     * @return
     */
    <E> List<E> findObjectByKey(List<? extends Serializable> keys, Class<E> clz);

    /**
     * sql查询,适用查询结果单行的场景；
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @param clz    指定返回的list中存放的对象的class,如String.class,Integer.Class,Double.Class
     * @param <E>    返回类型
     * @return 返回查询结果
     */
    default <E> E querySingleObject(String sql, Map<String, Object> params, Class<E> clz, boolean strictMode) {
        return querySingleObject(sql, (Object) params, clz, strictMode);
    }

    /**
     * sql查询,适用查询结果单行的场景；
     *
     * @param sql    sql语句
     * @param params 传参可以是实体对象
     * @param clz    指定返回的list中存放的对象的class,如String.class,Integer.Class,Double.Class
     * @return 返回类型
     */
    <E> E querySingleObject(String sql, Object params, Class<E> clz, boolean strictMode);

    /**
     * sql查询，适用查询结果为单行的场景；
     * 如果sql语句中只有一列,那jsonarray中存放的是该列的数组["1","2","3"...] 如果sql语句中返回不止一列,那么jsonarray中存放的是该列的json对象,例如 [{name:"1",age:"19"}...].
     *
     * @param sql    sql查询语句,
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合的json字符串。
     */
    default String querySingleString(String sql, Map<String, Object> params) {
        return JSONObject.toJSONString(queryMapList(sql, params));
    }

    /**
     * sql查询,用查询结果单行的场景；
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回查询结果的第一列的集合, 列名全部小写
     */
    default Map<String, Object> querySingleMap(String sql, Map<String, Object> params) {
        return querySingleObject(sql, params, Map.class, false);
    }

    /**
     * sql查询,用查询结果单行的场景；
     *
     * @param sql        sql语句
     * @param params     参数键值对,in/not in的参数 是数组
     * @param strictMode 严格模式  true时严格模式，返回多条则抛出异常，false时返回第一行
     * @return 返回查询结果的第一列的集合, 列名全部小写
     */
    default Map<String, Object> querySingleMap(String sql, Map<String, Object> params, boolean strictMode) {
        return querySingleObject(sql, params, Map.class, strictMode);
    }

    /**
     * sql查询.
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合
     */
    List<Map<String, Object>> queryMapList(String sql, Map<String, Object> params);

    /**
     * sql查询.
     *
     * @param sql             sql语句
     * @param params          参数键值对,in/not in的参数 是数组
     * @param pageNum         分页页数
     * @param pageSize        分页数量
     * @param isTotalRequired 是否返回总数
     * @return 返回PageResult对象，如果isTotalRequired为true 则返回总数；getTotalRow:总数；getList:数据集合;getTotalPage 总页数；
     */
    default PageResult<Map<String, Object>> queryMapListPageable(String sql, Map<String, Object> params, int pageNum, int pageSize, boolean isTotalRequired) {
        PageRequest<Map<String, Object>> request = DefaultPageRequest.of(pageNum, pageSize, isTotalRequired);
        return BeetlUtils.executePageable(sql, params, request, Map.class);
    }

    /**
     * sql查询.
     *
     * @param sql             sql语句
     * @param params          参数键值对,in/not in的参数 是数组
     * @param pageNum         分页页数
     * @param pageSize        分页数量
     * @param isTotalRequired 是否返回总数
     * @return 返回PageResult对象，如果isTotalRequired为true 则返回总数；getTotalRow:总数；getList:数据集合;getTotalPage 总页数；
     */
    default <E> PageResult<E> queryEntityListPageable(String sql, Map<String, Object> params, int pageNum, int pageSize, boolean isTotalRequired, Class<E> clz) {
        PageRequest<E> request = DefaultPageRequest.of(pageNum, pageSize, isTotalRequired);
        return BeetlUtils.executePageable(sql, params, request, clz);
    }

    /**
     * 根据sql查询对象集合
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回指定的clz对象的集合
     */
    default <E> List<E> queryEntityList(String sql, Map<String, Object> params, Class<E> clz) {
        return queryEntityList(sql, (Object) params, clz);
    }

    /**
     * 根据sql查询对象集合
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回指定的clz对象的集合
     */
    <E> List<E> queryEntityList(String sql, Object params, Class<E> clz);

    /**
     * sql查询,适用查询结果单行的场景；使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回查询结果
     */
    <E> E querySingleObjectFromMarkdown(String fileName, String sqlMark, Map<String, Object> params, Class<E> clz);


    /**
     * sql查询,用查询结果单行的场景；使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回查询结果的第一列的集合, 列名全部小写
     */
    default Map<String, Object> querySingleMapFromMarkdown(String fileName, String sqlMark, Map<String, Object> params) {
        return querySingleObjectFromMarkdown(fileName, sqlMark, params, Map.class);
    }


    /**
     * sql查询，适用查询结果为单行的场景；使用Markdown格式来组织SQL文件
     * 如果sql语句中只有一列,那jsonarray中存放的是该列的数组["1","2","3"...] 如果sql语句中返回不止一列,那么jsonarray中存放的是该列的json对象,例如 [{name:"1",age:"19"}...].
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合的json字符串。
     */
    default String querySingleStringFromMarkdown(String fileName, String sqlMark, Map<String, Object> params) {
        return JSONObject.toJSONString(queryMapListFromMarkDown(fileName, sqlMark, params));
    }

    /**
     * 使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合, 列名全部小写
     */
    List<Map<String, Object>> queryMapListFromMarkDown(String fileName, String sqlMark, Map<String, Object> params);

    /**
     * 使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合, 列名全部小写
     */
    <E> List<E> queryEntityListFromMarkDown(String fileName, String sqlMark, Map<String, Object> params, Class<E> clz);

    /**
     * 根据主键删除，需要严格匹配EntityClass.
     *
     * @param key   主键
     * @param clazz EntityClass类型
     */
    <E> void deleteEntityByKey(Serializable key, Class<E> clazz);

    /**
     * 存在该对象则更新，不存在则增加.
     *
     * @param entity 任意类型对象
     * @return 主键
     */
    <E> Object saveEntity(E entity);

    /**
     * 批量更新or新增，通过主键来判断是新增还是删除
     *
     * @param list 对象/实体列表
     */
    <E> boolean[] saveBatch(List<E> list);

    /**
     * 批量新增或更新；
     * TODO 已对Mysql进行了处理，Oracle，达梦（DM），人大金仓（Kingbase） 是使用  MERGE 的方式；神州通用（KingBaseES）不能使用 values 函数
     *
     * @param list           实体列表
     * @param uniqueKeyNames 数据库表对应的：组合唯一索引的实体字段
     * @param <E>            实体类型
     */
    <E> void upsertByKey(List<E> list, String[] uniqueKeyNames);

    /**
     * 新增或查询，需要注意：
     * uniqueKeyNames如果包含了主键，主键被申明@Autoid和@SeqID正常新增；@AssignID时无法进行新增；
     *
     * @param obj            实体对象
     * @param uniqueKeyNames 数据库表对应的：组合唯一索引的实体字段
     */
    <E> void upsertByKey(E obj, String[] uniqueKeyNames);

    /**
     * 部分更新，实体类中属性为Null或不传入的则不被更新
     *
     * @param list 任意类型对象List,未考虑到数据库能接收的最大量，因此，还需要程序自己控制每批的数量，设置成每批3000个比较通用
     */
    <E> void updateBatchIfNotNull(Class clazz, List<E> list);

    /************************delete data api ************************/
    /**
     * 删除任意类型对象.
     *
     * @param entity 任意类型对象
     */
    <E> int deleteEntity(E entity);

    /************************add data api ************************/

    /**
     * 添加对象，不需要严格匹配EntityClass，返回对象的主键.
     *
     * @param entity 实体
     * @return 主键
     */
    <E> Object addEntity(E entity);

    /************************update data api ************************/

    /**
     * 更新操作，不需要严格匹配EntityClass.
     *
     * @param entity 实体
     * @return 主键
     */
    <E> Object updateEntity(E entity);


    /**
     * 批量更新操作
     *
     * @param list 实体列表
     * @return 主键
     */
    <E> int[] updateBatch(List<E> list);

    /**
     * 部分更新，实体类中属性为Null则不被更新，
     * 注意注意：若实体中使用了存在默认值的类型，如下
     * byte：默认值为 0
     * short：默认值为 0
     * int：默认值为 0
     * long：默认值为 0L
     * float：默认值为 0.0f
     * double：默认值为 0.0d
     * char：默认值为 '\u0000'（空字符）
     * boolean：默认值为 false
     * 在使用部分更新时，若没有显式的赋值，会将数据库更新为默认值，请使用updateifNotNull(Class target, Object obj)
     *
     * @param entity 任意类型对象
     */
    <E> void updateIfNotNull(E entity);

    /**
     * 数据库操作.
     *
     * @param sql      sql语句
     * @param valuemap 参数键值对,注意:in/not in的参数 是数组
     * @return 返回执行行数
     */
    Integer sqlOperater(String sql, Map valuemap);

}
